/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.editor;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.Font;
import java.awt.Insets;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.FontMetrics;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.BorderFactory;
import javax.swing.SwingConstants;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.BevelBorder;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import javax.swing.text.JTextComponent;
import javax.swing.text.Caret;
/**
* Status bar support
*
* @author Miloslav Metelka
* @version 1.00
*/
public class StatusBar implements PropertyChangeListener, SettingsChangeListener {
public static final String CELL_MAIN = "main"; // NOI18N
public static final String CELL_POSITION = "position"; // NOI18N
public static final String CELL_TYPING_MODE = "typing-mode"; // NOI18N
public static final String INSERT_LOCALE = "status-bar-insert"; // NOI18N
public static final String INSERT_DEFAULT = "INS"; // NOI18N
public static final String OVERWRITE_LOCALE = "status-bar-overwrite"; // NOI18N
public static final String OVERWRITE_DEFAULT = "OVR"; // NOI18N
private static final String[] POS_MAX_STRINGS = new String[] { "99999:999" }; // NOI18N
private static final Insets NULL_INSETS = new Insets(0, 0, 0, 0);
static final Border CELL_BORDER
= BorderFactory.createCompoundBorder(
BorderFactory.createBevelBorder(BevelBorder.LOWERED),
BorderFactory.createEmptyBorder(0, 2, 0, 2)
);
protected ExtUI extUI;
/** The status bar panel into which the cells are added. */
private JPanel panel;
private boolean visible;
private Coloring coloring;
private Coloring boldColoring;
private List cellList = new ArrayList();
private CaretListener caretL;
private int caretDelay;
private boolean overwriteModeDisplayed;
private String insText;
private String ovrText;
static final long serialVersionUID =-6266183959929157349L;
public StatusBar(ExtUI extUI) {
this.extUI = extUI;
caretDelay = 500;
caretL = new CaretListener(caretDelay);
insText = LocaleSupport.getString(INSERT_LOCALE, INSERT_DEFAULT);
ovrText = LocaleSupport.getString(OVERWRITE_LOCALE, OVERWRITE_DEFAULT);
// Add caret listener
JTextComponent c = extUI.getComponent();
if (c != null) {
Caret caret = c.getCaret();
if (caret != null) {
caret.addChangeListener(caretL);
}
}
Settings.addSettingsChangeListener(this);
extUI.addPropertyChangeListener(this);
settingsChange(null);
}
public void settingsChange(SettingsChangeEvent evt) {
Class kitClass = Utilities.getKitClass(extUI.getComponent());
String settingName = (evt != null) ? evt.getSettingName() : null;
if (kitClass != null) {
Coloring dc = extUI.getDefaultColoring();
coloring = extUI.getColoring(Settings.STATUS_BAR_COLORING);
boldColoring = extUI.getColoring(Settings.STATUS_BAR_BOLD_COLORING);
// assign coloring
if (coloring != null) {
coloring = coloring.apply(dc);
} else {
coloring = dc;
}
// assign bold coloring
if (boldColoring != null) {
boldColoring = boldColoring.apply(dc);
} else {
boldColoring = dc;
}
// apply coloring to the status bar components
refreshPanel();
if (settingName == null || Settings.STATUS_BAR_CARET_DELAY.equals(settingName)) {
caretDelay = SettingsUtil.getInteger(kitClass, Settings.STATUS_BAR_CARET_DELAY,
DefaultSettings.defaultStatusBarCaretDelay);
if (caretL != null) {
caretL.setDelay(caretDelay);
}
}
if (settingName == null || Settings.STATUS_BAR_VISIBLE.equals(settingName)) {
boolean wantVisible = SettingsUtil.getBoolean(kitClass,
Settings.STATUS_BAR_VISIBLE, false);
setVisible(wantVisible);
}
}
}
protected JPanel createPanel() {
return new JPanel(new GridBagLayout());
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean v) {
if (v != visible) {
visible = v;
if (panel != null || visible) {
if (visible) { // need to refresh first
refreshPanel();
}
getPanel().setVisible(visible);
}
}
}
public final JPanel getPanel() {
if (panel == null) {
panel = createPanel();
initPanel();
}
return panel;
}
protected void initPanel() {
addCell(CELL_POSITION, POS_MAX_STRINGS).setHorizontalAlignment(
SwingConstants.CENTER);
addCell(CELL_TYPING_MODE, new String[] { insText, ovrText }).setHorizontalAlignment(
SwingConstants.CENTER);
setText(CELL_TYPING_MODE, insText);
addCell(CELL_MAIN, null);
}
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (ExtUI.COMPONENT_PROPERTY.equals(propName)) {
if (evt.getNewValue() != null) { // just installed
JTextComponent c = extUI.getComponent();
c.addPropertyChangeListener(this);
Caret caret = c.getCaret();
if (caret != null) {
caret.addChangeListener(caretL);
}
settingsChange(null);
refreshPanel();
} else { // just deinstalled
JTextComponent c = (JTextComponent)evt.getOldValue();
c.removePropertyChangeListener(this);
Caret caret = c.getCaret();
if (caret != null) {
caret.removeChangeListener(caretL);
}
}
} else if ("caret".equals(propName)) {
Caret oldCaret = (Caret)evt.getOldValue();
Caret newCaret = (Caret)evt.getNewValue();
if (oldCaret != null) {
oldCaret.removeChangeListener(caretL);
}
if (newCaret != null) {
newCaret.addChangeListener(caretL);
}
}
}
public int getCellCount() {
return cellList.size();
}
public JLabel addCell(String name, String[] widestStrings) {
return addCell(-1, name, widestStrings);
}
public JLabel addCell(int i, String name, String[] widestStrings) {
Cell c = new Cell(name, widestStrings);
addCellImpl(i, c);
return c;
}
public void addCustomCell(int i, JLabel c) {
addCellImpl(i, c);
}
private void addCellImpl(int i, JLabel c) {
synchronized (cellList) {
ArrayList newCellList = new ArrayList(cellList); // copy because of iterators
int cnt = newCellList.size();
if (i < 0 || i > cnt) {
i = cnt;
}
newCellList.add(i, c);
cellList = newCellList;
}
refreshPanel();
}
public JLabel getCellByName(String name) {
Iterator i = cellList.iterator();
while (i.hasNext()) {
JLabel c = (JLabel)i.next();
if (name.equals(c.getName())) {
return c;
}
}
return null;
}
public String getText(String cellName) {
JLabel cell = getCellByName(cellName);
return (cell != null) ? cell.getText() : null;
}
public void setText(String cellName, String text) {
setText(cellName, text, null);
}
public void setBoldText(String cellName, String text) {
setText(cellName, text, boldColoring);
}
public void setText(String cellName, String text,
Coloring extraColoring) {
// Should use invokeLater()?
JLabel cell = getCellByName(cellName);
if (cell != null) {
Coloring c = coloring;
if (extraColoring != null) {
c = extraColoring.apply(c);
}
c.apply(cell);
cell.setText(text);
}
}
/* Refresh the whole panel by removing all the components
* and adding only those that appear in the cell-list.
*/
private void refreshPanel() {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
if (isVisible()) { // refresh only if visible
// apply the coloring
Iterator it = cellList.iterator();
while (it.hasNext()) {
JLabel c = (JLabel)it.next();
if (c instanceof Cell) {
coloring.apply(c);
}
}
// layout the cells
GridBagConstraints gc = new GridBagConstraints();
gc.gridx = GridBagConstraints.RELATIVE;
gc.gridwidth = 1;
gc.gridheight = 1;
Iterator i = cellList.iterator();
while (i.hasNext()) {
JLabel c = (JLabel)i.next();
boolean main = CELL_MAIN.equals(c.getName());
if (main) {
gc.fill = GridBagConstraints.HORIZONTAL;
gc.weightx = 1.0;
}
getPanel().add(c, gc);
if (main) {
gc.fill = GridBagConstraints.NONE;
gc.weightx = 0;
}
}
}
}
}
);
}
class CaretListener implements ChangeListener, ActionListener {
Timer timer;
CaretListener(int delay) {
timer = new Timer(delay, this);
timer.setRepeats(false);
}
void setDelay(int delay) {
timer.setDelay(delay);
timer.setInitialDelay(delay);
}
public void stateChanged(ChangeEvent evt) {
timer.restart();
}
public void actionPerformed(ActionEvent evt) {
JTextComponent component = extUI.getComponent();
if (component != null) {
Caret caret = component.getCaret();
BaseDocument doc = Utilities.getDocument(extUI.getComponent());
if (caret != null && doc != null) {
int pos = caret.getDot();
String s = Utilities.debugPosition(doc, pos);
setText(CELL_POSITION, s);
Boolean b = (Boolean)extUI.getProperty(ExtUI.OVERWRITE_MODE_PROPERTY);
boolean om = (b != null && b.booleanValue());
if (om != overwriteModeDisplayed) {
overwriteModeDisplayed = om;
setText(CELL_TYPING_MODE, overwriteModeDisplayed ? ovrText : insText);
}
}
}
}
}
static class Cell extends JLabel {
Dimension maxDimension;
String[] widestStrings;
static final long serialVersionUID =-2554600362177165648L;
Cell(String name, String[] widestStrings) {
setName(name);
setBorder(CELL_BORDER);
setOpaque(true);
this.widestStrings = widestStrings;
}
private void updateSize() {
Font f = getFont();
if (maxDimension == null) {
maxDimension = new Dimension();
}
if (f != null) {
Border b = getBorder();
Insets ins = (b != null) ? b.getBorderInsets(this) : NULL_INSETS;
FontMetrics fm = getFontMetrics(f);
int mw = fm.stringWidth(this.getText());
maxDimension.height = fm.getHeight() + ins.top + ins.bottom;
if (widestStrings != null) {
for (int i = 0; i < widestStrings.length; i++) {
mw = Math.max(mw, fm.stringWidth(widestStrings[i]));
}
}
maxDimension.width = mw + ins.left + ins.right;
}
}
public Dimension getPreferredSize() {
if (maxDimension == null) {
maxDimension = new Dimension();
}
return new Dimension(maxDimension);
}
public void setFont(Font f) {
super.setFont(f);
updateSize();
}
}
}
/*
* Log
* 18 Gandalf-post-FCS1.14.1.2 4/5/00 Miloslav Metelka status bar patch2
* 17 Gandalf-post-FCS1.14.1.1 3/16/00 Miloslav Metelka fixed #5999
* 16 Gandalf-post-FCS1.14.1.0 3/8/00 Miloslav Metelka
* 15 Gandalf 1.14 3/8/00 Miloslav Metelka project creating dedlok
* fix
* 14 Gandalf 1.13 1/13/00 Miloslav Metelka
* 13 Gandalf 1.12 1/4/00 Miloslav Metelka
* 12 Gandalf 1.11 12/28/99 Miloslav Metelka
* 11 Gandalf 1.10 11/14/99 Miloslav Metelka
* 10 Gandalf 1.9 11/8/99 Miloslav Metelka
* 9 Gandalf 1.8 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 8 Gandalf 1.7 8/27/99 Miloslav Metelka
* 7 Gandalf 1.6 8/17/99 Ian Formanek Generated serial version
* UID
* 6 Gandalf 1.5 8/17/99 Miloslav Metelka
* 5 Gandalf 1.4 7/26/99 Miloslav Metelka
* 4 Gandalf 1.3 7/22/99 Miloslav Metelka
* 3 Gandalf 1.2 7/21/99 Miloslav Metelka
* 2 Gandalf 1.1 7/20/99 Miloslav Metelka
* 1 Gandalf 1.0 7/9/99 Miloslav Metelka
* $
*/